﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using NasuTek.Shion.Agent;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using WeifenLuo.WinFormsUI.Docking;

namespace NasuTek.Shion.Extencibility
{
    /// <summary>
    /// Contains functions to manage plugins
    /// </summary>
    public class ExtencibilityManager
    {
        public delegate void WhoIsEventHandler(object sender);
        public delegate void OnConsoleWriteHandler(object sender, string server, string message);

        public event WhoIsEventHandler WhoIsHandler;
        public event OnConsoleWriteHandler OnConsoleWrite;

        public void WhoIsHandled(object sender)
        {
            if (WhoIsHandler != null)
            {
                WhoIsHandler(sender);
            }
        }

        public void ConsoleWrite(string server, string message)
        {
            if (OnConsoleWrite != null)
            {
                OnConsoleWrite(this, server, message);
            }
        }
        Dictionary<string, Alias> _Aliases = new Dictionary<string, Alias>();
        Dictionary<string, OnCommand> _OnMessage = new Dictionary<string, OnCommand>();
        Dictionary<string, OnCommand> _OnNotice = new Dictionary<string, OnCommand>();
        Dictionary<string, OnRaw> _OnRaw = new Dictionary<string, OnRaw>();

        public Dictionary<string, OnRaw> OnRaw
        {
            get { return _OnRaw; }
            set { _OnRaw = value; }
        }
        public Dictionary<string, OnCommand> OnNotice
        {
            get { return _OnNotice; }
            set { _OnNotice = value; }
        }
        Dictionary<string, OnCommand> _OnAction = new Dictionary<string, OnCommand>();

        public Dictionary<string, OnCommand> OnAction
        {
            get { return _OnAction; }
            set { _OnAction = value; }
        }

        Dictionary<string, IrcClient> _Clients = new Dictionary<string, IrcClient>();
        Dictionary<string, Theme> _Themes = new Dictionary<string, Theme>();
        Dictionary<string, List<string>> _HostMasks = new Dictionary<string, List<string>>();
        WhoIs _WhoIsData = new WhoIs();

        public WhoIs WhoIsData
        {
            get { return _WhoIsData; }
            set { _WhoIsData = value; }
        }

        public class WhoIs
        {
            public string WhoIsUser;
            public string WhoIsServer;
            public string WhoIsOperator;
            public string WhoIsIdle;
            public string WhoIsChannels;
            public bool Handled = false;

            public void CleanUpWhoIsData()
            {
                WhoIsChannels = null;
                WhoIsServer = null;
                WhoIsIdle = null;
                WhoIsOperator = null;
                WhoIsUser = null;
                Handled = false;
            }
        }
        Dictionary<string, PluginData> _Plugins = new Dictionary<string, PluginData>();

        public Dictionary<string, PluginData> Plugins
        {
            get { return _Plugins; }
            set { _Plugins = value; }
        }

        public class PluginData
        {
            public PluginData(string name, string copyright, string author, string description, Version version)
            {
                Name = name;
                Copyright = copyright;
                Author = author;
                Description = description;
                Version = version;
            }

            string _Name, _Copyright, _Author, _Description;

            public string Description
            {
                get { return _Description; }
                set { _Description = value; }
            }

            public string Author
            {
                get { return _Author; }
                set { _Author = value; }
            }

            public string Copyright
            {
                get { return _Copyright; }
                set { _Copyright = value; }
            }

            public string Name
            {
                get { return _Name; }
                set { _Name = value; }
            }

            Version _Version;

            public Version Version
            {
                get { return _Version; }
                set { _Version = value; }
            }

        }
        public Dictionary<string, List<string>> HostMasks
        {
            get { return _HostMasks; }
            set { _HostMasks = value; }
        }

        ContextMenuStrip _NickMenu = new ContextMenuStrip();
        ToolStripMenuItem _ToolsAddinsMenu;
        DockPanel _Panel;

        public DockPanel Panel
        {
            get { return _Panel; }
            set { _Panel = value; }
        }

        public ToolStripMenuItem ToolsAddinsMenu
        {
            get { return _ToolsAddinsMenu; }
            set { _ToolsAddinsMenu = value; }
        }

        ListView _NickListView = null;
        public string activeServer, activeChannel;

        /// <summary>
        /// Nick List View
        /// </summary>
        public ListView NickListView
        {
            get { return _NickListView; }
            set { _NickListView = value; }
        }

        /// <summary>
        /// Right Click Nick Menu
        /// </summary>
        public ContextMenuStrip NickMenu
        {
            get { return _NickMenu; }
            set { _NickMenu = value; }
        }

        /// <summary>
        /// Contains all OnCommand's for reseaved Messages
        /// </summary>
        public Dictionary<string, OnCommand> OnMessage
        {
            get { return _OnMessage; }
            set { _OnMessage = value; }
        }

        /// <summary>
        /// Holds Client Dictionary from Form1 (Shion Client)
        /// </summary>
        public Dictionary<string, IrcClient> Clients
        {
            get { return _Clients; }
            set { _Clients = value; }
        }

        /// <summary>
        /// Holds Themes
        /// </summary>
        public Dictionary<string, Theme> Themes
        {
            get { return _Themes; }
            set { _Themes = value; }
        }

        public ExtencibilityManager(Dictionary<string, IrcClient> clients)
        {
            Clients = clients;
        }

        /// <summary>
        /// Contains Aliases
        /// </summary>
        public Dictionary<string, Alias> Aliases
        {
            get { return _Aliases; }
            set { _Aliases = value; }
        }

        /// <summary>
        /// Register a plugin into the PluginManager
        /// </summary>
        /// <param name="fileName">Path to Plugin</param>
        public void RegisterNewPlugin(string fileName)
        {
            InvokeMethod(fileName, "Plugin", "Load", new object[] { this });
        }

        /// <summary>
        /// Get a theme from the Theme dictionary
        /// </summary>
        /// <param name="p">Name of theme</param>
        /// <returns>Theme</returns>
        public Theme GetTheme(string p)
        {
            try { return Themes[p]; }
            catch (KeyNotFoundException) { return new Theme(); }
        }

        Object InvokeMethod(string AssemblyName, string ClassName, string MethodName, Object[] args)
        {
            // load the assemly

            Assembly assembly = Assembly.LoadFrom(AssemblyName);

            // Walk through each type in the assembly looking for our class

            foreach (Type type in assembly.GetTypes())
            {
                if (type.IsClass == true)
                {
                    if (type.FullName.EndsWith("." + ClassName))
                    {
                        // create an instance of the object

                        object ClassObj = Activator.CreateInstance(type);

                        // Dynamically Invoke the method

                        object Result = type.InvokeMember(MethodName,
                          BindingFlags.Default | BindingFlags.InvokeMethod,
                               null,
                               ClassObj,
                               args);
                        return (Result);
                    }
                }
            }
            throw (new System.Exception("could not invoke method"));
        }

        public string Address(string server, string nick, int mode)
        {
            string returnval = "";
            foreach (string nickhostmask in HostMasks[server])
            {
                if(Regex.Match(nickhostmask, "(?<nick>(.*))!(.*)").Groups["nick"].ToString() == nick)
                {
                    string nickmode = nickhostmask;
                    Match a = Regex.Match(nickmode, "(?<nick>(.*))!(?<user>(.*))@(?<host>(.*))");
                    string[] host = a.Groups["host"].ToString().Split('.');
                    host[0] = "*";
                    string hostNew = String.Join(".", host);

                    /*
                    0: *!user@host 
                    1: *!*user@host
                    2: *!*@host
                    3: *!*user@*.host
                    4: *!*@*.host
                    5: nick!user@host
                    6: nick!*user@host
                    7: nick!*@host
                    8: nick!*user@*.host
                    9: nick!*@*.host
                    */

                    switch (mode)
                    {
                        case 0:
                            returnval = String.Format("*!{0}@{1}", a.Groups["user"], a.Groups["host"]);
                            break;
                        case 1:
                            returnval = String.Format("*!*{0}@{1}", a.Groups["user"], a.Groups["host"]);
                            break;
                        case 2:
                            returnval = String.Format("*!*@{0}", a.Groups["host"]);
                            break;
                        case 3:
                            returnval = String.Format("*!*{0}@*.{1}", a.Groups["user"], hostNew);
                            break;
                        case 4:
                            returnval = String.Format("*!*@*.{*}", a.Groups["user"], hostNew);
                            break;
                        case 5:
                            returnval = String.Format("{0}!{1}@{2}", a.Groups["nick"], a.Groups["user"], a.Groups["host"]);
                            break;
                        case 6:
                            returnval = String.Format("{0}!*{1}@{2}", a.Groups["nick"], a.Groups["user"], a.Groups["host"]);
                            break;
                        case 7:
                            returnval = String.Format("{0}!*@{1}", a.Groups["nick"], a.Groups["host"]);
                            break;
                        case 8:
                            returnval = String.Format("{0}!*{1}@{2}", a.Groups["nick"], a.Groups["user"], hostNew);
                            break;
                        case 9:
                            returnval = String.Format("{0}!*@{1}", a.Groups["nick"], hostNew);
                            break;
                        default:
                            break;
                    }
                    break;
                }
            }
            return returnval;
        }
    }
}